package ihm.actions;

import ihm.views.options.ATKjOptionPane;
import ihm.views.preferences.DataBaseBox;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JOptionPane;

import systems.configurations.SystemConfiguration;
import systems.exceptions.database.BadConfigException;
import systems.languages.MultiLanguages;

public class DataBaseSaveAction implements ActionListener{

  private DataBaseBox dataBaseBox;
  private List<String> config;

  public DataBaseSaveAction(DataBaseBox dataBaseBox)
  {
    this.dataBaseBox = dataBaseBox;
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    loadNewConfig();
    try {
      checkNewConfig();
      saveNewConfig();
      SystemConfiguration.reload();
      ATKjOptionPane.showMessageDialog(this.dataBaseBox,
          MultiLanguages.getProperties("dialog.DBconfig.confirm"), 
          this.dataBaseBox.getTitle(), 
          JOptionPane.INFORMATION_MESSAGE, 
          null);
      this.dataBaseBox.dispose();
    } catch (BadConfigException e1) {
      ATKjOptionPane.showMessageDialog(this.dataBaseBox,
          MultiLanguages.getProperties("exception.BadConfiguration").replaceAll("\\$n ", "\n "),
          this.dataBaseBox.getTitle()+" - "+MultiLanguages.getProperties("exception.genericTitle"),
          JOptionPane.ERROR_MESSAGE, null);
    }
  }

  /**
   * Load the new database configuration into the class.
   */
  private void loadNewConfig()
  {
    this.config = dataBaseBox.getNewConfig();
  }

  /**
   * Check if all the config parameters are defined. If one of them
   * is empty or contains space character then the new configuration is not 
   * correct and an exception will be throw.
   * @throws BadConfigException - The exception when the new configuration
   * seems to be incorrect.
   */
  private void checkNewConfig() throws BadConfigException
  {
    for(String str: this.config)
    {
      if(str.isEmpty() || str.contains(" "))
        throw new BadConfigException();
    }
  }


  private void saveNewConfig()
  {
    String configPath = SystemConfiguration.getConfigFilePath();
    List<String> file;
    // 1 - Read data from the config file
    file = readFile(configPath);
    // 2 - Replace old data by new one
    replaceConfig(file, this.config);
    // 3 - Write new config
    writeFile(file, configPath);
  }

  
  private List<String> readFile(String pathToFile)
  {
    List<String> fileStrings = new LinkedList<String>();
    String currentLine;
    BufferedReader br;
    
    try {
      //Instanciate the BufferedReader
      br = new BufferedReader(new FileReader(pathToFile));
      //Read each line ...
      while((currentLine = br.readLine()) != null)
      {
        if(currentLine.isEmpty())
          continue;
        //... and store it
        fileStrings.add(currentLine);
      }
      //Close the BufferedReader
      br.close();
    } catch (FileNotFoundException e) {
      ATKjOptionPane.showMessageDialog(this.dataBaseBox,
          MultiLanguages.getProperties("exception.FileNotFound").replaceAll("\\$1 ", pathToFile),
          this.dataBaseBox.getTitle()+" - "+MultiLanguages.getProperties("exception.genericTitle"),
          JOptionPane.ERROR_MESSAGE, null);
    } catch (IOException e) {
      ATKjOptionPane.showMessageDialog(this.dataBaseBox,
          MultiLanguages.getProperties("exception.IOException").replaceAll("\\$n ", "\n")+e.getLocalizedMessage(),
          this.dataBaseBox.getTitle()+" - "+MultiLanguages.getProperties("exception.genericTitle"),
          JOptionPane.ERROR_MESSAGE, null);
    }
    
    return fileStrings;
  }
  
  private void replaceConfig(List<String> file, List<String> newConfig)
  {
    /*
     *  <entry key="db.driver">com.mysql.jdbc.Driver</entry>
     *  <entry key="db.url">jdbc:mysql://127.0.0.1/aion</entry>
     *  <entry key="db.remote.user">root</entry>
     *  <entry key="db.remote.pass">toor</entry>
     */
    int lineNb = 0;
    int done = 0; 
    for(String fileString : file)
    {
      if(done > 4)
        return;
      
      if(fileString.contains("<entry key=\"db.driver\">"))
      {
        file.set(lineNb, "<entry key=\"db.driver\">"+newConfig.get(0)+"</entry>");
        done ++;
      }
      
      if(fileString.contains("<entry key=\"db.url\">"))
      {
        String fullUrl = "jdbc:"+newConfig.get(1);
        fullUrl += (fullUrl.endsWith("/")?"":"/");
        fullUrl += newConfig.get(2);
        file.set(lineNb, "<entry key=\"db.url\">"+fullUrl+"</entry>");
        done += 2;
      }
      
      if(fileString.contains("<entry key=\"db.user\">"))
      {
        file.set(lineNb, "<entry key=\"db.user\">"+newConfig.get(3)+"</entry>");
        done ++;
      }
      if(fileString.contains("<entry key=\"db.root\">"))
      {
        file.set(lineNb, "<entry key=\"db.root\">"+newConfig.get(4)+"</entry>");
        done ++;
      }
      lineNb++;
    }
  }
  
  private void writeFile(List<String> file, String pathToFile)
  {
    BufferedWriter bw;
    
    try {
      //Instanciate the BufferedWriter
      bw = new BufferedWriter(new FileWriter(pathToFile));
      //Read each line ...
      for(String line : file)
      {
        bw.write(line+"\n");
      }
      //Close the BufferedWriter
      bw.close();
    } catch (FileNotFoundException e) {
      ATKjOptionPane.showMessageDialog(this.dataBaseBox,
          MultiLanguages.getProperties("exception.FileNotFound").replaceAll("\\$1 ", pathToFile),
          this.dataBaseBox.getTitle()+" - "+MultiLanguages.getProperties("exception.genericTitle"),
          JOptionPane.ERROR_MESSAGE, null);
    } catch (IOException e) {
      ATKjOptionPane.showMessageDialog(this.dataBaseBox,
          MultiLanguages.getProperties("exception.IOException").replaceAll("\\$n ", "\n")+e.getLocalizedMessage(),
          this.dataBaseBox.getTitle()+" - "+MultiLanguages.getProperties("exception.genericTitle"),
          JOptionPane.ERROR_MESSAGE, null);
    }
  }
}
